package com.rainbow.redis.plus.core.starter;

import java.time.Duration;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.rainbow.redis.plus.core.RedisSampleService;
import com.rainbow.redis.plus.core.RedisService;
import com.rainbow.redis.plus.core.starter.properties.RedisPlusProperties;

@Configuration
@EnableConfigurationProperties({RedisPlusProperties.class})
public class RedisPlusAutoConfiguration {
	
	@SuppressWarnings("rawtypes")
	@Bean
	public LettuceConnectionFactory lettuceConnectionFactory(RedisPlusProperties redisPlusProperties) throws Exception {
		// 连接池配置
		GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
		poolConfig.setMaxIdle(redisPlusProperties.getMaxIdle());
		poolConfig.setMinIdle(redisPlusProperties.getMaxIdle());
		poolConfig.setMaxTotal(redisPlusProperties.getMaxTotal());
		poolConfig.setMaxWaitMillis(redisPlusProperties.getMaxWait());
		LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration
				.builder()
				.commandTimeout(Duration.ofMillis(redisPlusProperties.getConnectTimeout()))//链接超时时间
				.poolConfig(poolConfig)
				.build();
		
		if (StringUtils.isNotBlank(redisPlusProperties.getNodes())) {
			
			 RedisClusterConfiguration redisConfig = new RedisClusterConfiguration();
			 Set<RedisNode> nodeses = new HashSet<>(); 
			 String[] hosts = redisPlusProperties.getNodes().split(","); 
			 
			 for (String h : hosts) { 
				 h = h.replaceAll("\\s","").replaceAll("\n", ""); 
				 if (!"".equals(h)) { 
					 String host = h.split(":")[0];
					 int port = Integer.valueOf(h.split(":")[1]); 
					 nodeses.add(new RedisNode(host,port)); 
				 } 
			 }
			 redisConfig.setClusterNodes(nodeses); // 跨集群执行命令时要遵循的最大重定向数量
			 redisConfig.setMaxRedirects(3); 
			 redisConfig.setPassword(redisPlusProperties.getPassword());
			 
			return new LettuceConnectionFactory(redisConfig, lettucePoolingClientConfiguration);
		}else if (StringUtils.isNotBlank(redisPlusProperties.getHost())) {
			// 单机redis
			RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
			String host = redisPlusProperties.getHost();
			redisConfig.setHostName(host == null || "".equals(host) ? "localhost" : host.split(":")[0]);
			redisConfig.setPort(Integer.valueOf(host == null || "".equals(host) ? "6379" : host.split(":")[1]));
			String password = redisPlusProperties.getPassword();
			if (password != null && !"".equals(password)) {
				redisConfig.setPassword(password);
			}
			redisConfig.setDatabase(redisPlusProperties.getDatabase());
			
			return new LettuceConnectionFactory(redisConfig, lettucePoolingClientConfiguration);
			
		}else {
			throw new Exception("redis 配置必要要有 host 或 nodes");
		}
	}

	@Bean
	@ConditionalOnMissingBean
	public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(lettuceConnectionFactory);

		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
		// 设置值（value）的序列化采用Jackson2JsonRedisSerializer。
		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
		// 设置键（key）的序列化采用StringRedisSerializer。
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());

		redisTemplate.afterPropertiesSet();

		return redisTemplate;
	}
	
    @Bean
    public RedisService redisSampleService() {
    	return new RedisSampleService();
    }
}